package org.legzo.castorranker;

import java.io.BufferedReader;
import java.io.FileReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.io.IOUtils;
import org.legzo.castorranker.ranker.Game;
import org.legzo.castorranker.ranker.Player;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DataLoader {

	private static Logger logger = LoggerFactory.getLogger(DataLoader.class);

	private SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
	private SimpleDateFormat completeFormat = new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss");

	private String dataFile;
	private List<Player> loadedPlayers = new ArrayList<Player>();
	private List<Game> games = new ArrayList<Game>();

	public DataLoader(String dataFile) {
		this.dataFile = dataFile;
	}

	public void loadData() {
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(dataFile));

			String strLine = br.readLine();
			// Read File Line By Line
			treatHeader(strLine);
			while ((strLine = br.readLine()) != null) {
				games.add(treatGameLine(strLine));
			}

			br.close();
		} catch (Exception e) {
			logger.error("Error occured", e);
		} finally {
			IOUtils.closeQuietly(br);
		}

		// fillBlanksInChronology();
	}

	private Game treatGameLine(String strLine) throws ParseException {
		StringTokenizer tokenizer = new StringTokenizer(strLine, ";");
		int colIndex = 0;

		Date dateOfLine = null;
		Game currentGame = null;

		while (tokenizer.hasMoreTokens()) {

			String value = tokenizer.nextToken();
			if (colIndex == 0) {
				if (value.matches("[0-9]{4}/[0-9]{2}/[0-9]{2}")) {
					dateOfLine = format.parse(value);
				} else {
					dateOfLine = completeFormat.parse(value);
				}
				currentGame = new Game(dateOfLine);
			} else {
				Player player = loadedPlayers.get(colIndex - 1);
				int playerScore = Integer.parseInt(value);
				if (playerScore > 0)
					currentGame.addPlayer(player, playerScore);
			}
			colIndex++;
		}

		currentGame.rankPlayers();

		return currentGame;
	}

	private void treatHeader(String strLine) {
		StringTokenizer tokenizer = new StringTokenizer(strLine, ";");

		while (tokenizer.hasMoreTokens()) {
			String value = tokenizer.nextToken();

			if ("date".equals(value)) {
				// do nothing, it's the date column
			} else {
				Player player = new Player(value);
				loadedPlayers.add(player);
			}
		}
	}

	public static String getCurrentGlobalRanking(Collection<Player> players, final Date d) {
		StringBuffer sb = new StringBuffer();

		List<Player> ranking = new ArrayList<Player>();

		ranking.addAll(players);

		Comparator<Player> rankingComparator = new Player.RankingComparator(d);
		Collections.sort(ranking, rankingComparator);

		for (Player player : ranking) {
			Game lastPlayedGame = player.getLastPlayedGame(d);
			Long lastRanking = 1200l;

			if (lastPlayedGame != null) {
				lastRanking = player.getRankings().get(lastPlayedGame);
			}

			sb.append(ranking.indexOf(player) + 1).append("/ ").append(player.getName()).append(": ").append(
					lastRanking).append(" (").append(player.getRankingVariationForDate(d)).append(")\n");
		}

		return sb.toString();
	}

	public static String getCurrentGlobalRankingForDate(Collection<Player> players, final Date date) {
		StringBuffer sb = new StringBuffer();

		List<Player> ranking = new ArrayList<Player>();

		ranking.addAll(players);

		Collections.sort(ranking, new Player.RankingComparator(date));

		for (Player player : ranking) {
			sb.append(ranking.indexOf(player) + 1).append("/ ").append(player.getName()).append(": ").append(
					player.getRanking()).append("\n");
		}

		return sb.toString();
	}

	public List<Player> getLoadedPlayers() {
		return loadedPlayers;
	}

	public void setDataFile(String dataFile) {
		this.dataFile = dataFile;
	}

	public List<Game> getGames() {
		return games;
	}
}
